/************************************************************************

								Heroes IV
					  Copyright 2000, The 3DO Company

	------------------------------------------------------------------
  						       player.h

	$Header: /game/player.h $

	$NoKeywords: $

 ************************************************************************/

#ifndef PLAYER_H_INCLUDED
#define PLAYER_H_INCLUDED

#if _MSC_VER > 1000
#pragma once
#endif // _MSC_VER > 1000

#include <vector>

#include "abstract_grail_data_source.h"
#include "adv_dwelling_list.h"
#include "adv_object_type.h"
#include "adventure_object.h"
#include "adventure_object_ptr.h"
#include "army_array_ptr.h"
#include "artifact_type.h"
#include "caravan_set.h"
#include "creature_type.h"
#include "difficulty_level.h"
#include "map_rect.h"
#include "material_array.h"
#include "material_values.h"
#include "mine_ptr.h"
#include "ownable_garrisonable_adv_object_list.h"
#include "quest_site_list.h"
#include "sanctuary_list.h"
#include "sized_int_types.h"
#include "town_building_set.h"
#include "town_list.h"
#include "town_list_ptr.h"
#include "vector_set.h"

int const k_player_army_limit = 8;
int const k_artifact_type_evaluation_count = k_artifact_level_relic + 1;

class t_adv_dwelling;
enum  t_ai_importance;
class t_army;
class t_caravan;
class t_creature_stack;
class t_lighthouse;
enum  t_map_size;
class t_ownable_garrisonable_adv_object;
enum  t_player_color;
class t_town;
enum  t_town_building;
enum  t_town_type;

// ------------------------------------------------------------------
// player data structure 
// ------------------------------------------------------------------
class t_player : public t_abstract_grail_data_source
{
public:
	typedef t_adventure_object::t_visibility_overlay t_visibility_overlay;
	typedef t_vector_set< t_creature_stack * > t_creature_stack_set;

	t_player();
	t_player( bool computer, int team );

	void											add( t_adv_dwelling * dwelling );
	void											add( t_caravan * caravan );
	void						                    add( t_quest_origin_site* quest_site );
	void										    add( t_mine* mine );
	void										    add_army( t_army* army );
	void											add_lighthouse( t_lighthouse* lighthouse );
	void											add_object( t_adventure_object* object );
	void											add_garrison( t_ownable_garrisonable_adv_object * garrison );
	void											add_graveyard( t_army* army );
	void											add( t_sanctuary* sanctuary );
	void											add_town( t_town* town );
	void											ai_calculate_resource_demand(int day);
	void											ai_calculate_reserved_funds( int day = -1 );
	void											ai_start_turn(t_adventure_map& map);
	float											ai_get_artifact_value( t_artifact_level level ) const;
	t_material_array const&							ai_get_discretionary_funds() const;
	int												ai_get_discretionary_amount( int material ) const;
	void											ai_set_discretionary_amount( int material, int amount );
	void											ai_set_discretionary_funds( t_material_array const& funds );
	void											ai_spend_discretionary( t_material_array const& amount );
	bool						                    can_create_army() const;
	void											clear_max_level();
	t_creature_stack_set							build_creature_stack_set() const;
	void											eliminate();
	void											force_elimination();
	void											force_garrison_visits();
	void											fractional_gain( t_material material, int amount );
	void										    gain( t_material material, int amount );
	void										    gain( t_material_array const& materials );
	t_ai_importance									get_ai_importance() const;
	t_town_type									    get_alignment() const;
	t_army_array*									get_armies();
	t_army_array const*								get_armies() const;
	int												get_battle_score() const;
	unsigned										get_battles_won() const;
	t_uint8											get_building_delay() const;
	t_caravan_set const &							get_caravans() const;
	t_player_color									get_color() const;
	t_adv_dwelling_list	const &						get_dwellings() const;
	t_material_array const &						get_fractional_funds() const;
	t_material_array const &						get_funds() const;
	t_ownable_garrisonable_adv_object_list const &	get_garrisons() const;
    t_material_array								get_income( int day ) const;
	int												get_lighthouse_count() const;
	int												get_magic_dampener_bonus() const;
	std::string	const &								get_name() const;
	float											get_material_value(int material) const;
	t_material_values const &						get_material_values() const;
	t_uint16										get_max_level() const;
	int												get_necromancy_amplifier_bonus() const;
    int											    get_obelisk_count( t_obelisk_color color ) const;
    //std::string const &                             get_income_text( int day, int material ) const;
    void                                            get_income_text( int day, int material, std::string &income_text );
    t_quest_site_list const &                       get_quest_origin_sites() const;
	int												get_quests_completed_count() const;
	t_sanctuary_list const&							get_sanctuary_list() const;
	int											    get_team() const;
	int 								            get_total_army_experience() const;
	t_town_list*								    get_towns();
	int											    get_town_count() const;
	float											get_weekly_creature_growth( int level ) const;
	t_material_array								get_valued_funds( t_material_array const& materials ) const;
	virtual bool									gets_global_grail_effects( t_town_type alignment ) const;
	bool										    has_key( int key ) const;
	bool											has_lost() const;
	bool											has_max_level() const;
	void											initialize( bool computer_budget,
																t_difficulty difficulty );
	void											inc_battle_score( int score );
    void											inc_obelisk_count( t_obelisk_color color );
	void											inc_quests_completed();
	bool									        is_computer() const;
	bool											is_eliminated() const;	
	void											mark_visibility(
														int						level,
														t_visibility_overlay &	visibility_overlay ) const;
	void											on_begin_turn();
	void											on_end_turn();
	bool							                read( std::streambuf& stream, int version );
	void											remove( t_adv_dwelling * dwelling );
	void											remove( t_caravan * caravan );
	void									        remove( t_quest_origin_site* quest_site );
	void										    remove( t_mine* mine );
	void										    remove_army( t_army* army );
	void											remove_lighthouse( t_lighthouse* lighthouse );
	void											remove_garrison( t_ownable_garrisonable_adv_object * garrison );
	void											remove_graveyard( t_army* army );
	void											remove( t_sanctuary* sanctuary );
	void											remove_object( t_adventure_object* object );
	void									        remove_town( t_town* town );
	bool											seen_town_booster( t_town_building building ) const;
	void											set_ai_importance( t_ai_importance importance );
	void									        set_color( t_player_color color );
	void						                    set_alignment( t_town_type arg );
	void											set_funds( t_material_array const& funds );
	void											set_key( int key, bool set = true );
	void											set_max_level( t_uint16 max_level );
	void											set_material_values( t_material_values const& values);
	void											set_name( std::string const& name );
	void											set_seen_town_booster( t_town_building building );
	void											set_to_computer( void );
	void											set_to_player( bool is_computer );
	void						                    spend( t_material material, int amount );
	void											spend( t_material_array const& cost );
//	void											update_scouting_visibility_for_object( t_adventure_object const & update_obj );
	bool							                write( std::streambuf& buffer ) const;

protected:
	void									ai_calculate_artifact_values();
	void									ai_calculate_artifact_values( t_creature_array const& army, int* count);
	void									common_construct();

	float									m_ai_artifact_value[k_artifact_type_evaluation_count];
	t_material_array						m_ai_discretionary_funds;
	t_ai_importance							m_ai_importance;
	t_material_array						m_ai_reserved_funds;
	t_town_type							    m_alignment;
	t_army_array_ptr					    m_armies;
	int										m_battle_points;
	unsigned								m_battles_won;
	t_caravan_set							m_caravans;
	t_player_color						    m_color;
	bool									m_computer;
	t_adv_dwelling_list						m_dwelling_list; 
	bool									m_eliminated;
	bool									m_force_elimination;
	t_material_array						m_fractional_funds;
	t_material_array					    m_funds;
	float									m_creature_growth[k_creature_level_count];
	bool									m_has_max_level;
	t_army_array_ptr						m_graveyards;
	bool									m_key[k_border_guard_color_count];
    std::string                             m_income_text;
	int										m_lighthouse_count;
	t_material_values						m_material_values;
	t_uint16								m_max_level;
	std::vector<t_mine_ptr>					m_mines;
	std::string								m_name;	
	int										m_quests_completed;
	int										m_obelisk_count[k_obelisk_color_count];
	t_ownable_garrisonable_adv_object_list	m_owned_garrisons;
	std::vector<t_adventure_object_ptr>		m_owned_objects;
	t_quest_site_list 	                    m_quest_origin_sites;
	t_sanctuary_list						m_sanctuary_list;
	t_town_building_set						m_seen_booster_messages;
	int										m_team;
	t_town_list_ptr							m_towns;
};

// ------------------------------------------------------------------
// inlines for t_player
// ------------------------------------------------------------------
inline t_ai_importance t_player::get_ai_importance() const
{
	return m_ai_importance;
}

inline t_town_type t_player::get_alignment() const
{
	return m_alignment;
}

inline t_caravan_set const & t_player::get_caravans() const
{
	return m_caravans;
}

inline t_player_color t_player::get_color() const
{
	return m_color;
}

inline t_adv_dwelling_list const & t_player::get_dwellings() const
{
	return m_dwelling_list;
}

inline t_material_array const& t_player::get_fractional_funds() const
{
	return m_fractional_funds;
}

inline t_material_array const& t_player::get_funds() const
{
	return m_funds;
}

inline int t_player::get_lighthouse_count() const
{
	return m_lighthouse_count;
}

inline void t_player::set_funds( t_material_array const& funds )
{
	m_funds = funds;
}

inline std::string const& t_player::get_name() const
{
	return m_name;
}

inline int	t_player::get_town_count() const
{
	return m_towns->size();
}

inline t_quest_site_list const& t_player::get_quest_origin_sites() const
{
	return m_quest_origin_sites;
}
        
inline void t_player::gain( t_material material, int amount )
{
	if ( (m_funds[material] += amount) < 0) 
		m_funds[material] = 0;
}

inline void t_player::gain( t_material_array const& materials )
{
	for (int i = 0; i < t_material_array::k_size; i++)
	{
		if ( (m_funds[i] += materials[i]) < 0)
			m_funds[i] = 0;
	}
}

inline int t_player::get_battle_score() const
{
	return m_battle_points;
}

inline unsigned t_player::get_battles_won() const
{
	return m_battles_won;
}

inline t_uint16 t_player::get_max_level() const
{
	return m_max_level;
}

inline int t_player::get_quests_completed_count() const
{
	return m_quests_completed;
}

inline int t_player::get_team() const
{
	return m_team;
}

inline bool t_player::has_max_level() const
{
	return m_has_max_level;
}

inline void t_player::inc_battle_score( int score )
{
	assert( score >= 0 );	// Why a negative score for (we assume) winning?
	m_battles_won++;
	m_battle_points += score;
}

inline void t_player::inc_quests_completed()
{
	++m_quests_completed;
}

inline bool t_player::is_computer() const
{
	return m_computer;
}

inline bool t_player::seen_town_booster( t_town_building building ) const
{
	return m_seen_booster_messages[ building ];
}

inline void t_player::set_ai_importance( t_ai_importance importance )
{
	m_ai_importance = importance;
}

inline void t_player::set_alignment( t_town_type arg )
{
	m_alignment = arg;
}

inline void t_player::set_color( t_player_color color )
{
	m_color = color;
}

inline void t_player::set_max_level( t_uint16 max_level )
{
	m_max_level = max_level;
	m_has_max_level = true;
}

inline void t_player::set_name( std::string const& name )
{
	m_name = name;
}


inline void t_player::set_seen_town_booster( t_town_building building )
{
	m_seen_booster_messages.set( building );
}

inline void t_player::set_to_computer( void )
{
	m_computer			= true;
}

inline void t_player::set_to_player( bool is_computer )
{
	m_computer			= is_computer;
}

inline void t_player::spend( t_material material, int amount )
{
	m_funds[material] -= amount;
}

inline void t_player::spend( t_material_array const& cost )
{
	m_funds -= cost;
}

// ------------------------------------------------------------------
// stand alone functions
// ------------------------------------------------------------------
inline bool same_team( t_player const* player_1, t_player const* player_2 )
{
	
	if (player_1 == player_2)
		return true;
	return player_1 != 0 && player_2 != 0 && player_1->get_team() == player_2->get_team();
}

// Return true if we have two different LIVING players on the same team
inline bool is_ally( t_player const* player_1, t_player const* player_2 )
{
	if (player_1 == player_2)
		return false;

	if (!player_1 || !player_2)
		return false;

	if (player_1->get_team() != player_2->get_team())
		return false;

	return !(player_1->is_eliminated() || player_2->is_eliminated());
}

int const k_minimum_retreat_distance = 10;

t_town* find_nearest_town( t_adventure_map *	  map,
						   t_player*			  player,
						   t_adv_map_point const& location,
						   t_adv_map_point &	  target_location,
						   t_creature_array *     army,
						   t_town const*		  excluded_town,
						   bool *                 enemy_adjacent_towns_found,
						   bool *				  blocked_towns_found,
						   bool					  check_enemy_adjacency,
						   int					  minimum_distance = k_minimum_retreat_distance,
						   bool *				  nearby_town_found = 0 );

int calculate_battle_victory_points( t_creature_array const &	victor, 
									 t_creature_array const &	defeated,	
									 t_creature_array const &	victor_losses,
									 t_creature_array const &	defeated_losses,
									 t_map_size					map_size );

t_material_array get_initial_budget( t_difficulty difficulty );

#endif // PLAYER_H_INCLUDED
